package com.web_bloks.linkers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;

import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.linker.PublicResource;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.AbstractLinker;
import com.google.gwt.core.ext.linker.Artifact;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.linker.IFrameLinker;

@SuppressWarnings("all")
@LinkerOrder(LinkerOrder.Order.POST)
public class ManifestLinker extends AbstractLinker {
	
	private static final String PROPERTY_NAME = "Property Name";
    private static final String PROPERTY_VALUE = "Property Value";
    
    private int maxPropertyNameLength = PROPERTY_NAME.length();
    private int maxPropertyValueLength = PROPERTY_VALUE.length();

	private MySelectionScriptLinker ssl = new MySelectionScriptLinker();
	
	private StringBuilder sb = new StringBuilder();

	
	public String getDescription() {
        return "ManifestLinker";
    }
	
	public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts)
    	throws UnableToCompleteException {

		// Sort the artifacts.
        List<Artifact> artifactsInOrder = new ArrayList<Artifact>(artifacts);
        Collections.sort(artifactsInOrder, new Comparator<Artifact>() {
            public int compare(Artifact a1, Artifact a2) {
                int rc = a1.getClass().getName().compareTo(a2.getClass().getName());
                if (rc == 0) {
                    return a1.compareTo(a2);
                } else {
                    return rc;
                }
            }
        });
        // Collect the paths for all of the emitted artifacts so that we can check later
        // that the path calculation is working for the compilation results.
        Set<String> emittedArtifactPaths = new HashSet<String>();
        for (Artifact artifact : artifactsInOrder) {
            if (artifact instanceof EmittedArtifact) {
                emittedArtifactPaths.add(((EmittedArtifact) artifact).getPartialPath());
                
            }
            
            if (artifact instanceof PublicResource) {
            	sb.append("Public resource: "+ ((PublicResource) artifact).getPartialPath() );
            }
            
        }
     // Output information for each of the compilation results. 
        for (Artifact artifact : artifactsInOrder) {
            if (artifact instanceof CompilationResult) {
                final CompilationResult compilationResult = (CompilationResult) artifact;
                // The path for this compilation result.
                String artifactPath = ssl.getPath(logger, context, compilationResult);
                // Check that the path matches one of the EmittedArtifacts. This is to give us
                // warning if the path calculation is changed.
                if (!emittedArtifactPaths.contains(artifactPath)) {
                    System.out.println("No EmittedArtifact with path " + artifactPath);
                    throw new UnableToCompleteException();
                }
                // Output all of the permutations for this result.
                SortedSet<SortedMap<SelectionProperty, String>> permutations = compilationResult.getPropertyMap();
                for (SortedMap<SelectionProperty, String> permutation : permutations) {
                    sb.append("Permutation\n");
                    sb.append("===========\n");
                    sb.append(artifactPath);
                    sb.append("\n");
                    propertyValueHeader();
                    for (Map.Entry<SelectionProperty, String> propertyValue : permutation.entrySet()) {
                        outputPadded(propertyValue.getKey().getName(), maxPropertyNameLength);
                        sb.append("   ");
                        outputPadded(propertyValue.getValue(), maxPropertyValueLength);
                        sb.append("\n");
                    }
                    sb.append("\n");
                }
            }
        }

        // Create a new set of artifacts that we can modify and return.
        ArtifactSet toReturn = new ArtifactSet(artifacts);
        // Add the manifest as a new artifact to the set that we're returning.
        toReturn.add(emitString(logger, sb.toString(), "manifest.txt"));
        
        return toReturn;
        
	}
	
	/**
     * Output the header for a set of property values.
     */
    private void propertyValueHeader() {
        outputPadded(PROPERTY_NAME, maxPropertyNameLength);
        sb.append("   ");
        outputPadded(PROPERTY_VALUE, maxPropertyValueLength);
        sb.append("\n");
        for (int i = 0; i < maxPropertyNameLength + maxPropertyValueLength + 3; i++) {
            sb.append("-");
        }
        sb.append("\n");
    }

    /**
     * Output a string padded with spaces on the right to the provided length.
     *
     * @param s The string.
     * @param length The length for the output.
     */
    private void outputPadded(String s, int length) {
        sb.append(s);
        for (int i = 0; i < length - s.length(); i++) {
            sb.append(' ');
        }
    }

    private static class MySelectionScriptLinker extends IFrameLinker {

        private String getPath(TreeLogger treeLogger, LinkerContext context, CompilationResult compilationResult)
                throws UnableToCompleteException {
            EmittedArtifact ea = doEmitCompilation(treeLogger, context, compilationResult);
            return ea.getPartialPath();
        }
    }
}
